package tarantula.instrumenter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import soot.Body;
import soot.BodyTransformer;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.jimple.IdentityStmt;
import soot.jimple.Jimple;
import soot.jimple.StaticInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.StringConstant;
import soot.tagkit.Tag;
import soot.util.Chain;

public class EveryStatementIntrumenter extends BodyTransformer {
	
	public static final String tarantula_package = "tarantula";

	@Override
	protected void internalTransform(Body body, String phase, Map options) {
		SootMethod method = body.getMethod();
		SootClass clazz = method.getDeclaringClass();
		String pkgName = clazz.getPackageName();
		String clazzName = clazz.getName(); // here we may use clazz.getShortName();
		
		System.out.println("Instrumenting method: " + method.getSignature());
		
		Chain units = body.getUnits();
		
		Iterator stmtIt = units.snapshotIterator();
		while (stmtIt.hasNext()) {
			Stmt stmt = (Stmt)stmtIt.next();
			System.out.println("   visit stmt: " + stmt);
			
			if( !(stmt instanceof IdentityStmt) ){ // we should not insert stmt before the identity statements
				Tag tag = stmt.getTag("LineNumberTag");
				String lnStr = "";
				if(tag == null){
					lnStr = "null";
				}else{
					lnStr = tag.toString();
				}
				
				List argList = new ArrayList();
				argList.add(StringConstant.v(pkgName)); // TODO: test for the classes in the default package
				argList.add(StringConstant.v(clazzName));	
				argList.add(StringConstant.v(lnStr));
				argList.add(StringConstant.v(stmt.toString()));
				
				SootMethod tracerMethod = Scene.v().getMethod("<tarantula.instrumenter.Tracer: void insertExecutedSourceCode(java.lang.String,java.lang.String,java.lang.String,java.lang.String)>");
				StaticInvokeExpr invokeExpr = Jimple.v().newStaticInvokeExpr(tracerMethod.makeRef(), argList);
				Stmt tracingStmt = Jimple.v().newInvokeStmt(invokeExpr);
				units.insertBefore(tracingStmt, stmt); // TODO: test whether the order of the arguments is correct
			}
		}
	} 

	
	
}
